package org.languageguide.user;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/** 
 * Utility methods for generating hashes of passwords, and validating passwords.
 *
 */
public class PasswordUtility {
    
    private static SecureRandom randomGenerator = null;

    static{
		try{
			randomGenerator = SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException ex){
			ex.printStackTrace();
		}
    }
	
    public static final String DIGEST_TYPE = "SHA-256";
    
    private PasswordUtility() {}
    
    
    /** Generates a hash of the input string, and returns the hash (encoded as a hexadecimal string.) */
    public static String getHash(String plaintext) {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance(DIGEST_TYPE);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException("can't instantiate "+DIGEST_TYPE+" digester", ex);
        }
        md.reset();
        byte[] hash = md.digest(plaintext.getBytes());
        return encodeHexString(hash);
    }
    
    /** Generates a hash of the input string, and returns the hash (encoded as a hexadecimal string.) */
    public static String getBase64Hash(String plaintext) {
    	return Base32.encode(plaintext.getBytes());
    }
    
    
    public static boolean matches(String plaintext, String hash) {
        
        // FIXME: this is potentially risky, should only be used during development
        if (hash == null) {
            return true;
        }
        
        String strInHash = getHash(plaintext);
        return strInHash.equalsIgnoreCase(hash);
    }
    
    
    
    
    private static String encodeHexString(byte[] bytes) {
        StringBuilder out = new StringBuilder(bytes.length * 2);
        for (int i=0; i<bytes.length; i++) {
            int byteValue = ((int) bytes[i]) & 0xff;
            String hex = Integer.toHexString(byteValue);
            if (hex.length() == 1) {
                out.append("0");
            }
            out.append(hex);
        }
        return out.toString();
    }
    public static String generateRandomPW() {
		if(randomGenerator == null)
			throw new RuntimeException("random generator does not exist");

		try {
			//generate a random number
			String randomNum = Integer.valueOf(randomGenerator.nextInt()).toString();

			//get its digest
			
			MessageDigest sha = MessageDigest.getInstance("SHA-1");
			byte[] result =  sha.digest(randomNum.getBytes());
			return Base32.encode(result).substring(0 ,8);

		} catch (NoSuchAlgorithmException ex) {
			ex.printStackTrace();
			throw new RuntimeException("unable to generate id");
		}
	}
    
    
    public static String generateSecureRandomString() {
		if(randomGenerator == null)
			throw new RuntimeException("random generator does not exist");

		try {
			//generate a random number
			String randomNum = Integer.valueOf(randomGenerator.nextInt()).toString();

			//get its digest
			MessageDigest sha = MessageDigest.getInstance("SHA-1");
			byte[] result =  sha.digest(randomNum.getBytes());
			return hexEncode(result);

		} catch (NoSuchAlgorithmException ex) {
			ex.printStackTrace();
			throw new RuntimeException("unable to generate id");
		}
	}
    
	/**
	 * The byte[] returned by MessageDigest does not have a nice
	 * textual representation, so some form of encoding is usually performed.
	 *
	 * This implementation follows the example of David Flanagan's book
	 * "Java In A Nutshell", and converts a byte array into a String
	 * of hex characters.
	 */
	private static String hexEncode( byte[] aInput){
		StringBuilder result = new StringBuilder(aInput.length * 2);
		char[] digits = {'0', '1', '2', '3', '4','5','6','7','8','9','a','b','c','d','e','f'};
		for ( int idx = 0; idx < aInput.length; ++idx) {
			byte b = aInput[idx];
			result.append( digits[ (b&0xf0) >> 4 ] );
			result.append( digits[ b&0x0f] );
		}
		return result.toString();
	}

    
}
